﻿using LogLib;
using System;
using System.Threading.Tasks;

namespace IPCPages
{
    /// <summary>
    /// 镜头瞄准服务类
    /// </summary>
    public class Aiming
    {
        /// <summary>
        /// 错误信息
        /// </summary>
        private string _error = "";
        public string Error
        {
            get { return _error; }
        }

        /// <summary>
        /// 测距传感器
        /// </summary>
        public Measuring Measurer = new Measuring();

        public bool IsComOpen
        {
            private set;
            get;
        }

        private AimingOption Options = new AimingOption();

        private MotionControl _motion = MotionControl.Instance;

        private int _movingTimes = 0;

        public event MeasuringCompletedEventHandler MeasuringCompleted;
        protected void OnMeasuringCompleted(MeasuringCompletedEventArgs e)
        {
            if (MeasuringCompleted != null)
            {
                MeasuringCompleted(this, e);
            }
        }

        private bool _bFirstAdjustFlag = false;

        public Aiming()
        {
            LoadConfig();
        }

        private void LoadConfig()
        {
            Options.Load();
        }

        public void Start()
        {
            _bFirstAdjustFlag = true;
            _movingTimes = 0;
            if (IsComOpen)
            {
                Measurer.StartWork();
            }
        }

        public void Stop()
        {
            if (IsComOpen)
            {
                Measurer.StopWork();
            }
        }

        public bool OpenService()
        {
            IsComOpen = Measurer.OpenCom();
            if (IsComOpen)
            {
                Measurer.MeasuringUpdated += OnMeasuringUpdated;
            }
            else
            {
                _error = Measurer.Error;
            }
            return IsComOpen;
        }

        public void CloseService()
        {          
            Measurer.CloseCom();
            IsComOpen = false;
            MeasuringCompleted = null;
        }

        /// <summary>
        /// 执行瞄准: 执行首次运动，使电机带动镜头运动到眼睛位置
        /// </summary>
        public void OnFirstAimTaking(int value)
        {
            Log.Write("测量得到当前身高是: " + value.ToString());
            // 镜头当前的位置
            double NowCamPos = (int)(_motion.CurrentCameraPos * Options.DistanceOfThousandStep / 1000 + Options.CamHeight);  
            // 当前头顶的位置，即人的身高
            double NowHeadTopPos = Options.SensorHeight - value;        
            // 当前眼睛的位置
            double NowEyePos = NowHeadTopPos - Options.EyesFormHeadtopHeight;
            // 计算需要移动的距离/ 步数
            double moveDistance = NowEyePos - NowCamPos; 
            // 计算需要移动的步数
            int movingSteps = (int)(Math.Abs(moveDistance) / Options.DistanceOfThousandStep * 1000);
            if (moveDistance > 0)
            {
                _motion.Up(movingSteps);
            }
            else
            {
                _motion.Down(movingSteps);
            }
        }

        /// <summary>
        /// 执行瞄准: 在首次运动之后，执行一般性的瞄准，使镜头运动到大致对准位置
        /// </summary>
        /// <param name="value">当前传感器的测量结果</param>
        public void OnGeneralAimTaking(int value)
        {
            Log.Write("测量得到当前身高是: " + value.ToString());
            // 镜头当前的位置
            double NowCamPos = (int)(_motion.CurrentCameraPos * Options.DistanceOfThousandStep / 1000 + Options.CamHeight);            
            // 当前头顶的位置，即人的身高
            double NowHeadTopPos = Options.SensorHeight - value;
            // 当前眼睛的位置
            double NowEyePos = NowHeadTopPos - Options.EyesFormHeadtopHeight;
            if (NowEyePos < Options.CamHeight)
            {
                Log.Write("身高太矮, 相机无法往下运动了.");
                return;
            }
            // 计算需要移动的距离/ 步数
            double moveDistance = NowEyePos - NowCamPos;                  
            // 计算需要移动的步数
            int movingSteps = (int)(Math.Abs(moveDistance) / Options.DistanceOfThousandStep * 1000);
            if (movingSteps < Options.MaximumError)
            {
                string strLog = string.Format("波动误差{0}<{1}, 不需要移动", movingSteps, Options.MaximumError);
                Log.Write(strLog);
                return;
            }
            if (moveDistance > 0)
            {
                _motion.Up(movingSteps);
            }
            else
            {
                _motion.Down(movingSteps);
            }
        }

        private void OnMeasuringUpdated(int value)
        {
            _movingTimes++;
            if (_bFirstAdjustFlag)
            {
                OnFirstAimTaking(value);
                WaitForMoveDone();
            }
            else
            {
                OnGeneralAimTaking(value);
                WaitForMoveDone();
            }           
        }

        private void OnMeasuringCompleted()
        {           
            OnMeasuringCompleted(new MeasuringCompletedEventArgs(true, 0, ""));
        }

        private void WaitForMoveDone()
        {
            Task.Factory.StartNew(() => 
            {
                if (_bFirstAdjustFlag)
                {
                    _motion.WaitForMovingDone();
                    _bFirstAdjustFlag = false;
                    Measurer.SetEvent();
                }
                else
                {
                    Measurer.StopWork();
                    OnMeasuringCompleted();
                }
            });
        }
    }
}
